package gui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Date;

import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.tree.TreePath;

import record.AllProjectsRecord;
import record.Directory;
import record.ProjectRecord;
import record.Record;
import request.AllProjectsRequest;
import request.LogoutRequest;
import request.NewProjectRequest;
import request.RemoveDirectoryRequest;
import request.RemoveProjectRequest;
import request.RequestFactory;
import request.RequestType;
import system.Client;

/**
 * A panel that allows the user to select the project they want to work on.
 * Also allows the user to create and delete projects.
 * @author Stephan
 *
 */
@SuppressWarnings("serial")
public class ProjectSelectionWindow extends JPanel implements ActionListener, ListSelectionListener
{
	/**
	 * A list of currently available projects
	 */
	private JList directoryScreen;
	/**
	 * The Open Project button.
	 */
	private JButton openProjectButton;
	/**
	 * The "Create Directory" Button
	 */
	private JButton createDirecotryButton;
	/**
	 * The "Create Project" Button
	 */
	private JButton createProjectButton;
	/**
	 * The "Delete Project" Button
	 */
	private JButton deleteProjectButton;
	/**
	 * The "Logout" button
	 */
	private JButton logoutButton;

	/**
	 * A panel to display metadata about the currently selected project.
	 */
	@SuppressWarnings("unused")
	private JLabel projectMetaData;
	/**
	 * A label which displays a hello message to the user.
	 */
	private JLabel helloLabel;
	
	/**
	 * An instance of the <code>Client</code>, through which this window will communicate with the
	 * server.
	 */
	private Client client;
	
	/**
	 * The currently selected <code>ProjectRecord</code>
	 */
	private ProjectRecord record;
	/**
	 * The application
	 */
	private Application app;
	
	/**
	 * A panel for displaying meta data about the currently selected project
	 */
	private JPanel metaDataPane;
	
	private RequestFactory factory = new RequestFactory();
	
	/**
	 * Updates the given application with the current window information.
	 * @param pApp the application which will be displaying this window.
	 */
	public ProjectSelectionWindow(Application pApp)
	{
		this.client = pApp.getClient();
		app = pApp;
		
		populateTree();
		
		openProjectButton = new JButton("Open Project");
		createDirecotryButton = new JButton("New Directory");
		createProjectButton = new JButton("New Project");
		deleteProjectButton = new JButton("Delete Project");
		logoutButton = new JButton("Logout");

		projectMetaData = new JLabel();
		helloLabel = new JLabel();

		openProjectButton.addActionListener(this);
		createProjectButton.addActionListener(this);
		deleteProjectButton.addActionListener(this);
		logoutButton.addActionListener(this);

		helloLabel.setText("<html>Welcome to GeoExplorer!" +
				"<br/><br/>" +
				"Select a project from below, or create a new project.");

		Container pane = this;
		pane.setLayout(new BorderLayout(5, 5));

		JPanel buttonPanel = new JPanel();
		buttonPanel.add(openProjectButton);
		buttonPanel.add(createProjectButton);
		//buttonPanel.add(createDirecotryButton);
		buttonPanel.add(deleteProjectButton);
		
		buttonPanel.add(logoutButton);

		JScrollPane treePane = new JScrollPane(directoryScreen);
		
		treePane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		treePane.setPreferredSize(new Dimension(300, 500));

		metaDataPane = new JPanel();
		metaDataPane.setPreferredSize(new Dimension(300, 500));
		metaDataPane.setLayout(new BoxLayout(metaDataPane,BoxLayout.Y_AXIS));
		
		directoryScreen.addListSelectionListener(this);

		JSplitPane splitPane = new JSplitPane();
		splitPane.setLeftComponent(treePane);
		splitPane.setRightComponent(metaDataPane);
		splitPane.setResizeWeight(.5);
		
		pane.add(buttonPanel, BorderLayout.PAGE_END);
		pane.add(splitPane, BorderLayout.CENTER);
		pane.add(helloLabel, BorderLayout.PAGE_START);

		this.setSize(new Dimension(630, 600));
		app.getContentPane().removeAll();
		app.getContentPane().add(this);
		this.setVisible(true);
		app.setVisible(true);
	}

	
	/**
	 * Fills the list of projects that the user can choose from.
	 */
	private void populateTree()
	{
		if(directoryScreen == null)
			directoryScreen = new JList();
		//Directory dir = new Directory("root");
		
		
		DefaultListModel lm = new DefaultListModel();
		
		try
		{
			AllProjectsRequest allProjects = (AllProjectsRequest)factory.getRequest(RequestType.AllProjects);
			AllProjectsRecord record = (AllProjectsRecord)client.sendRequest(allProjects);
			if(record == null)
				return;
			
			if(record.getRecords() == null)
				return;
			
			ProjectRecord[] projects = new ProjectRecord[record.getRecords().size()]; 
			projects = record.getRecords().toArray(projects);
			Arrays.sort(projects);
			for(ProjectRecord r : projects)
			{
				lm.addElement(r);
				
			}
//			for(ProjectRecord r : record.getRecords())
//			{
//				Directory x = dir.findDirectory(r.getPath());
//				if(x != null)
//					x.addProject(r);
//				else
//				{
//					Directory n = new Directory(r.getPath());
//					
//					if(false)
//						dir.addDirectory(x); 
//					
//					x.addDirectory(n);
//					n.addProject(r);
//				}				
//			}
			
			
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}
		directoryScreen.setModel(lm);
		directoryScreen.validate();
		directoryScreen.repaint();
		this.validate();
		
		directoryScreen.requestFocusInWindow();
		if(directoryScreen.getModel().getSize() > 0)
			directoryScreen.setSelectedIndex(0);
	}


	/**
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		try
		{
			if (e.getSource().equals(openProjectButton))
			{
				
				doOpen();
			}
			else if (e.getSource().equals(createDirecotryButton))
			{
				doCreateDirectory();
				populateTree();
			}
			else if (e.getSource().equals(createProjectButton))
			{
				doCreateProject();
				populateTree();
			}
			else if (e.getSource().equals(deleteProjectButton))
			{
				doDelete();
				populateTree();
			}
			else if (e.getSource().equals(logoutButton))
			{
				doLogout();
			}
		}
		catch (IOException ex)
		{

		}
		catch (ClassNotFoundException ex)
		{

		} catch (Exception a) {
			a.printStackTrace();
		}
	}
	
	/**
	 * Gets a copy of the currently selected project record.
	 * @return the currently selected <code>ProjectRecord</code> or <code>null</code>
	 * if no project record is selected.
	 */
	public ProjectRecord getProjectRecord()
	{
		return (record instanceof ProjectRecord ? (ProjectRecord)record : null);
	}

	/**
	 * Opens the currently selected project.
	 * @throws IOException if something bad happens
	 * @throws ClassNotFoundException if something bad happens
	 */
	private void doOpen() throws IOException, ClassNotFoundException
	{
//		if (directoryScreen.getSelectedValue() instanceof Directory)
//			JOptionPane.showMessageDialog(this, "Please select a project not a directory.");
//		else
		{
//			record = client.sendRequest(new ProjectRecordRequest(directoryScreen.getLastSelectedPathComponent().toString(), 
//					getNormalPath(directoryScreen.getSelectionPath())));
			
			
			record = (ProjectRecord) directoryScreen.getSelectedValue();
			if(record == null)
				return;
			((ProjectRecord) directoryScreen.getSelectedValue()).getMetaData().setLastOpened(new Timestamp(new Date().getTime()));
			new ProjectMenuWindow(record,app);
		}
	}

	/**
	 * Creates a directory.
	 */
	private void doCreateDirectory()
	{
//		if (directoryScreen.getSelectedValue() instanceof Directory)
//			JOptionPane.showInputDialog("Enter a directory name");
//		else
//		{
//			JOptionPane.showMessageDialog(this, "Please select a directory " + 
//					"to which you'd like to add a sub-directory.");
//			return;
//		}
		
	}

	/**
	 * Creates a project.
	 * @throws IOException if something bad happens
	 * @throws ClassNotFoundException if something bad happens
	 */
	private void doCreateProject() throws IOException, ClassNotFoundException
	{
		String projName = null;
//		if (directoryScreen.getSelectedValue() instanceof Directory)
			projName = JOptionPane.showInputDialog(this,"Enter a project name","Project Name",JOptionPane.PLAIN_MESSAGE);
			
		if(projName == null)
			return;
//		else
//		{
//			JOptionPane.showMessageDialog(this, "Please select a directory " + 
//					"to which you'd like to add a project.");
//			return;
//		}
	
//		String path = ((Directory)directoryScreen.getSelectedValue()).getPath();
		NewProjectRequest project = (NewProjectRequest)factory.getRequest(RequestType.NewProject);
		project.setProjectName(projName);
		project.setPath("");
		Record record = client.sendRequest(project);
		if(record == null)
		{
			JOptionPane.showMessageDialog(this, "Failed to create project","Failed Create Project",JOptionPane.ERROR_MESSAGE);
		}
	}
	
	/**
	 * Deletes the currently selected project.
	 * @throws IOException if something bad happens
	 * @throws ClassNotFoundException if something bad happens
	 */
	private void doDelete() throws IOException, ClassNotFoundException
	{
		if (directoryScreen.getSelectedIndices().length > 0)
		{
			int delete = 0;
			if (directoryScreen.getSelectedValue() instanceof Directory)
			{
//				if (directoryScreen.getSelectedVlue().equals(
//						directoryScreen.getModel().getRoot()))
//				{
//					JOptionPane.showMessageDialog(this,
//							"You cannot delete the root");
//					return;
//				}

				delete = JOptionPane.showConfirmDialog(this, "Are you sure you want to "
						+ "delete this directory and all of it's projects " + 
						"and sub directories: "
						+ directoryScreen.getSelectedValue() + "?","Delete?",JOptionPane.YES_NO_OPTION);
			}
			else
			{
				delete = JOptionPane.showConfirmDialog(this, "Are you sure you want to " +
						"delete the project: "
						+ directoryScreen.getSelectedValue() + "?","Delete?",JOptionPane.YES_NO_OPTION);
			}
			
			if(delete == JOptionPane.YES_OPTION)
			{
				//TreePath path = directoryScreen.getSelectionPath();
				
				if(directoryScreen.getSelectedValue() instanceof Directory)
				{
					Directory dir = (Directory)directoryScreen.getSelectedValue();
					RemoveDirectoryRequest remove = (RemoveDirectoryRequest)factory.getRequest(RequestType.RemoveDirectory);
					remove.setDirectory(dir);
					client.sendRequest(remove);
					
				}
				else if(directoryScreen.getSelectedValue() instanceof ProjectRecord)
				{
					ProjectRecord record = (ProjectRecord)directoryScreen.getSelectedValue();
					RemoveProjectRequest remove = (RemoveProjectRequest)factory.getRequest(RequestType.RemoveProject);
					remove.setRecord(record);
					client.sendRequest(remove);
				}
			}
			
		}
		else
			JOptionPane.showMessageDialog(this, "You need to select a " + 
					"project or directory to delete.","Select Project or Directory",JOptionPane.PLAIN_MESSAGE);
	}

	/**
	 * Ends the current session and returns to the login screen.
	 * @throws Exception if something bad happens
	 */
	private void doLogout() throws Exception
	{
		LogoutRequest logout = (LogoutRequest)factory.getRequest(RequestType.Logout);
		Record record = client.sendRequest(logout);
		if(record == null)
		{
			app.resetClient();
			new LoginWindow(app);
		}
	}
	
	/**
	 * Parses the path returned by the <code>JTree</code> and converts it into a 
	 * normal web style path.
	 * @param path the path to parse.
	 * @return the normalized path.
	 */
	@SuppressWarnings("unused")
	private String getNormalPath(TreePath path)
	{
		String normalPath = path.toString().replaceAll("\\[|\\]", "").replaceAll(", ", "/");
		return normalPath;	
	}
    
    /**
     * Updates the metadata panel for the currently selected panel
     * @param record the record for which to update the metadata
     */
	public void updateMetaData(ProjectRecord record)
	{
		metaDataPane.removeAll();
		JLabel nameOfProject = new JLabel("Project name: " + record.getName());
		JLabel projectCreated = new JLabel("Project created on: " + record.getMetaData().getDateCreated().toString());
		JLabel projectLastOpened = new JLabel("Project last opened on: " + record.getMetaData().getLastOpened().toString());
		JLabel projectLastSaved = new JLabel("Project last saved on: " + record.getMetaData().getLastSaved().toString());
		metaDataPane.add(nameOfProject);
		metaDataPane.add(projectCreated);
		metaDataPane.add(projectLastOpened);
		metaDataPane.add(projectLastSaved);
		metaDataPane.setVisible(true);
		metaDataPane.repaint();
		this.validate();
	}
	

	/**
	 * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
	 */
	@Override
	public void valueChanged(ListSelectionEvent arg0) {
		
		ProjectRecord record = (ProjectRecord)directoryScreen.getSelectedValue();
		if(record != null)
		{
			updateMetaData(record);
		}
		else
		{
			metaDataPane.removeAll();
			metaDataPane.repaint();
		}
		
	}

}
